package com.gx.util.base;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.gx.util.base.model.DistrictInfo;
import com.gx.util.base.model.IDCardInfo;
import com.gx.util.commonutil.DateUtil;
import com.gx.util.fileutil.PropertiesUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.Properties;

/**
 * @author gaoxing
 * @create 2018-05-26 上午10:08
 */
public class IDCardUtils {
    private static Map<String, String> provinces = ImmutableMap.<String,String>builder().put("11", "北京市").put("12", "天津市").put("13", "河北省").put("14", "山西省").put("15", "内蒙古自治区").put("21", "辽宁省").put("22", "吉林省").put("23", "黑龙江省").put("31", "上海市").put("32", "江苏省").put("33", "浙江省").put("34", "安徽省").put("35", "福建省").put("36", "江西省").put("37", "山东省").put("41", "河南省").put("42", "湖北省").put("43", "湖南省").put("44", "广东省").put("45", "广西壮族自治区").put("46", "海南省").put("50", "重庆市").put("51", "四川省").put("52", "贵州省").put("53", "云南省").put("54", "西藏自治区").put("61", "陕西省").put("62", "甘肃省").put("63", "青海省").put("64", "宁夏回族自治区").put("65", "新疆维吾尔自治区").put("71", "台湾省").put("81", "香港特别行政区").put("82", "澳门特别行政区").put("91", "国外").build();

    private static Map<String, DistrictInfo> districtInfoMap = Maps.newHashMapWithExpectedSize(5300);
    private static int[] powers = new int[]{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};

    static {
        Properties prop = PropertiesUtil.load("district-info.properties");
        prop.entrySet().forEach((entry) -> {
            districtInfoMap.put((String)entry.getKey(), JsonUtils.readValue((String)entry.getValue(), DistrictInfo.class));
        });
    }
    public static IDCardInfo parseIdCard(String idCard) {
        return parseIdCard(idCard, true);
    }
    public static IDCardInfo parseIdCard(String idCard, Boolean check) {
        if (StringUtils.isBlank(idCard) ||
                !(idCard.length() == 15 || idCard.length() == 18)){
            return null;
        }
        DistrictInfo districtInfo = districtInfo(idCard.substring(0, 6));

        IDCardInfo info = new IDCardInfo();
        info.setProvince(districtInfo.getProvince());
        info.setCity(districtInfo.getCity());
        info.setCounty(districtInfo.getCounty());


        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        int index = 14;
        if (idCard.length() == 15) {
            dateFormat = new SimpleDateFormat("yyMMdd");
            index = 12;
        }
        String birthDate = idCard.substring(6, index);
        if (StringUtils.isNumeric(birthDate)) {
            try {
                Date date = dateFormat.parse(birthDate);
                String tmpDate = dateFormat.format(date);
                if (!tmpDate.equals(birthDate)) {
                    return null;
                }

                info.setBirthDate(DateUtil.toDateFormat(date));
                info.setAge(DateUtil.compareYear(new Date(), date));
            } catch (ParseException var12) {
                return null;
            }
        }
        String sGender = idCard.substring(index + 2, index + 3);
        if (StringUtils.isNumeric(sGender)) {
            Integer gender = Integer.valueOf(idCard.substring(index + 2, index + 3));
            if ((gender.intValue() & 1) == 1) {
                info.setMale(true);
            } else {
                info.setMale(false);
            }
        }

        if (check.booleanValue() && idCard.length() == 18) {
            int cardSum = 0;
            char[] cardChars = idCard.substring(0, 17).toCharArray();

            int checkCode;
            for(checkCode = 0; checkCode < 17; ++checkCode) {
                cardSum += Integer.parseInt(String.valueOf(cardChars[checkCode])) * powers[checkCode];
            }

            checkCode = (12 - cardSum % 11) % 11;
            String sCheckCode = checkCode != 10 ? checkCode + "" : "X";
            if (!sCheckCode.equalsIgnoreCase(idCard.substring(17))) {
                return null;
            }
        }

        return info;



    }
    private static DistrictInfo districtInfo(String code) {
        if (districtInfoMap.containsKey(code)) {
            return districtInfoMap.get(code);
        } else {
            DistrictInfo districtInfo = new DistrictInfo();
            code = code.substring(0, 2);
            if (NumberUtils.isDigits(code) && provinces.containsKey(code)) {
                districtInfo.setProvince((String)provinces.get(code));
            }

            return districtInfo;
        }
    }


    public static void main(String[] args) {
        System.out.println(districtInfoMap.size());
//        System.out.println(districtInfoMap);

        System.out.println(parseIdCard("52240019800629601X"));;
        System.out.println(parseIdCard("440106197808301189"));;
        System.out.println(parseIdCard("37150219750320896X"));;
        System.out.println(parseIdCard("440106197808301189"));;
    }

}
